{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "Using TensorFlow backend.\n"
     ]
    }
   ],
   "source": [
    "from keras.models import model_from_json\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {},
   "outputs": [],
   "source": [
    "from inception_resnet_v1 import *\n",
    "import numpy as np\n",
    "\n",
    "from keras.models import Sequential\n",
    "from keras.models import load_model\n",
    "from keras.models import model_from_json\n",
    "from keras.layers.core import Dense, Activation\n",
    "from keras.utils import np_utils\n",
    "\n",
    "from keras.preprocessing.image import load_img, save_img, img_to_array\n",
    "from keras.applications.imagenet_utils import preprocess_input\n",
    "\n",
    "import matplotlib.pyplot as plt\n",
    "from keras.preprocessing import image"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 30,
   "metadata": {},
   "outputs": [],
   "source": [
    "face_model = InceptionResNetV1()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 31,
   "metadata": {},
   "outputs": [],
   "source": [
    "face_model.load_weights('facenet_weights.h5')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "metadata": {},
   "outputs": [],
   "source": [
    "def normalize(x):\n",
    "    return x / np.sqrt(np.sum(np.multiply(x, x)))\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 32,
   "metadata": {},
   "outputs": [],
   "source": [
    "def getEuclideanDistance(source, validate):\n",
    "    euclidean_dist = source - validate\n",
    "    euclidean_dist = np.sum(np.multiply(euclidean_dist, euclidean_dist))\n",
    "    euclidean_dist = np.sqrt(euclidean_dist)\n",
    "    return euclidean_dist"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 34,
   "metadata": {},
   "outputs": [],
   "source": [
    "def preprocess_data(image_path):\n",
    "    image = load_img(image_path, target_size=(160, 160))\n",
    "    image = img_to_array(image)\n",
    "    image = np.expand_dims(image, axis=0)\n",
    "    image = preprocess_input(image)\n",
    "    return image"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {},
   "outputs": [],
   "source": [
    "img1_representation = normalize(face_model.predict(preprocess_data('image_1.jpeg'))[0,:])\n",
    "img2_representation = normalize(face_model.predict(preprocess_data('image_2.jpeg'))[0,:])\n",
    " \n",
    "euclidean_distance = getEuclideanDistance(img1_representation, img2_representation)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "0.70589006"
      ]
     },
     "execution_count": 22,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "euclidean_distance"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "metadata": {},
   "outputs": [],
   "source": [
    "def getCosineSimilarity(source, validate):\n",
    "    a = np.matmul(np.transpose(source), validate)\n",
    "    b = np.sum(np.multiply(source, source))\n",
    "    c = np.sum(np.multiply(validate, validate))\n",
    "    return 1 - (a / (np.sqrt(b) * np.sqrt(c)))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 37,
   "metadata": {},
   "outputs": [],
   "source": [
    "img1_representation = (face_model.predict(preprocess_data('image_1.jpeg'))[0,:])\n",
    "img2_representation = (face_model.predict(preprocess_data('image_2.jpeg'))[0,:])\n",
    " \n",
    "cosine = getCosineSimilarity(img1_representation, img2_representation)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 38,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "0.2491404414176941"
      ]
     },
     "execution_count": 38,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "cosine"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#  import all the necessary libraries\n",
    "import cv2\n",
    "import imutils\n",
    "import numpy as np\n",
    "from sklearn.metrics import pairwise\n",
    "\n",
    "\n",
    "# global variables\n",
    "bg = None"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#-------------------------------------------------------------------------------\n",
    "# Function - To find the running average over the background\n",
    "#-------------------------------------------------------------------------------\n",
    "def run_avg(image, accumWeight):\n",
    "    global bg\n",
    "    # initialize the background\n",
    "    if bg is None:\n",
    "        bg = image.copy().astype(\"float\")\n",
    "        return\n",
    "\n",
    "    # compute weighted average, accumulate it and update the background\n",
    "    cv2.accumulateWeighted(image, bg, accumWeight)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#------------------------------------------------------------------------------#\n",
    "#segment function starts, to segment the region of hand in the image\n",
    "#-------------------------------------------------------------------------------\n",
    "def segment(image, threshold=25):\n",
    "    global bg\n",
    "    # find the absolute difference between background and current frame\n",
    "    diff = cv2.absdiff(bg.astype(\"uint8\"), image)\n",
    "\n",
    "    # threshold the diff image so that we get the foreground\n",
    "    thresholded = cv2.threshold(diff, threshold, 255, cv2.THRESH_BINARY)[1]\n",
    "\n",
    "    # get the contours in the thresholded image\n",
    "    (_, cnts, _) = cv2.findContours(thresholded.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)\n",
    "\n",
    "    # return None, if no contours detected\n",
    "    if len(cnts) == 0:\n",
    "        return\n",
    "    else:\n",
    "        # based on contour area, get the maximum contour which is the hand\n",
    "        segmented = max(cnts, key=cv2.contourArea)\n",
    "        return (thresholded, segmented)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#------------------------------------------------------------------------------#\n",
    "#segment function ends----------------------------------------------------------------------#\n",
    "\n",
    "# Function - To count the number of fingers in the segmented hand region\n",
    "#-------------------------------------------------------------------------------\n",
    "from sklearn.metrics import pairwise\n",
    "def count(thresholded, segmented):\n",
    "\t# find the convex hull of the segmented hand region\n",
    "\tchull = cv2.convexHull(segmented)\n",
    "\n",
    "\t# find the most extreme points in the convex hull\n",
    "\textreme_top    = tuple(chull[chull[:, :, 1].argmin()][0])\n",
    "\textreme_bottom = tuple(chull[chull[:, :, 1].argmax()][0])\n",
    "\textreme_left   = tuple(chull[chull[:, :, 0].argmin()][0])\n",
    "\textreme_right  = tuple(chull[chull[:, :, 0].argmax()][0])\n",
    "\n",
    "\t# find the center of the palm\n",
    "\tcX = int((extreme_left[0] + extreme_right[0]) / 2)\n",
    "\tcY = int((extreme_top[1] + extreme_bottom[1]) / 2)\n",
    "\n",
    "\t# find the maximum euclidean distance between the center of the palm\n",
    "\t# and the most extreme points of the convex hull\n",
    "\tdistance = pairwise.euclidean_distances([(cX, cY)], Y=[extreme_left, extreme_right, extreme_top, extreme_bottom])[0]\n",
    "\tmaximum_distance = distance[distance.argmax()]\n",
    "\t\n",
    "\t# calculate the radius of the circle with 80% of the max euclidean distance obtained\n",
    "\tradius = int(0.8 * maximum_distance)\n",
    "\t\n",
    "\t# find the circumference of the circle\n",
    "\tcircumference = (2 * np.pi * radius)\n",
    "\n",
    "\t# take out the circular region of interest which has \n",
    "\t# the palm and the fingers\n",
    "\tcircular_roi = np.zeros(thresholded.shape[:2], dtype=\"uint8\")\n",
    "\t\n",
    "\t# draw the circular ROI\n",
    "\tcv2.circle(circular_roi, (cX, cY), radius, 255, 1)\n",
    "\t\n",
    "\t# take bit-wise AND between thresholded hand using the circular ROI as the mask\n",
    "\t# which gives the cuts obtained using mask on the thresholded hand image\n",
    "\tcircular_roi = cv2.bitwise_and(thresholded, thresholded, mask=circular_roi)\n",
    "\n",
    "\t# compute the contours in the circular ROI\n",
    "\t(_, cnts, _) = cv2.findContours(circular_roi.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)\n",
    "\n",
    "\t# initalize the finger count\n",
    "\tcount = 0\n",
    "\n",
    "\t# loop through the contours found\n",
    "\tfor c in cnts:\n",
    "\t\t# compute the bounding box of the contour\n",
    "\t\t(x, y, w, h) = cv2.boundingRect(c)\n",
    "\n",
    "\t\t# increment the count of fingers only if -\n",
    "\t\t# 1. The contour region is not the wrist (bottom area)\n",
    "\t\t# 2. The number of points along the contour does not exceed\n",
    "\t\t#     20% of the circumference of the circular ROI\n",
    "\t\tif ((cY + (cY * 0.20)) > (y + h)) and ((circumference * 0.20) > c.shape[0]):\n",
    "\t\t\tcount += 1\n",
    "\n",
    "\treturn count"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#-------------------------------------------------------------------------------\n",
    "# Main function\n",
    "#-------------------------------------------------------------------------------\n",
    "if __name__ == \"__main__\":\n",
    "    # initialize accumulated weight\n",
    "    accumWeight = 0.5\n",
    "\n",
    "    # get the reference to the webcam\n",
    "    camera = cv2.VideoCapture(0)\n",
    "\n",
    "    # region of interest (ROI) coordinates\n",
    "    top, right, bottom, left = 20, 450, 325, 690\n",
    "\n",
    "    # initialize num of frames\n",
    "    num_frames = 0\n",
    "\n",
    "    # calibration indicator\n",
    "    calibrated = False\n",
    "\n",
    "    # keep looping, until interrupted\n",
    "    while(True):\n",
    "        # get the current frame\n",
    "        (grabbed, frame) = camera.read()\n",
    "\n",
    "        # resize the frame\n",
    "        frame = imutils.resize(frame, width=700)\n",
    "\n",
    "        # flip the frame so that it is not the mirror view\n",
    "        frame = cv2.flip(frame, 1)\n",
    "\n",
    "        # clone the frame\n",
    "        clone = frame.copy()\n",
    "\n",
    "        # get the height and width of the frame\n",
    "        (height, width) = frame.shape[:2]\n",
    "\n",
    "        # get the ROI\n",
    "        roi = frame[top:bottom, right:left]\n",
    "\n",
    "        # convert the roi to grayscale and blur it\n",
    "        gray = cv2.cvtColor(roi, cv2.COLOR_BGR2GRAY)\n",
    "        gray = cv2.GaussianBlur(gray, (7, 7), 0)\n",
    "\n",
    "        # to get the background, keep looking till a threshold is reached\n",
    "        # so that our weighted average model gets calibrated\n",
    "        if num_frames < 30:\n",
    "            run_avg(gray, accumWeight)\n",
    "            if num_frames == 1:\n",
    "            \tprint (\"Calibration is in progress...\")\n",
    "            elif num_frames == 29:\n",
    "                print (\"Calibration is successful...\")\n",
    "        else:\n",
    "            # segment the hand region\n",
    "            hand = segment(gray)\n",
    "\n",
    "            # check whether hand region is segmented\n",
    "            if hand is not None:\n",
    "                # if yes, unpack the thresholded image and\n",
    "                # segmented region\n",
    "                (thresholded, segmented) = hand\n",
    "\n",
    "                # draw the segmented region and display the frame\n",
    "                cv2.drawContours(clone, [segmented + (right, top)], -1, (0, 0, 255))\n",
    "                \n",
    "                # count the number of fingers\n",
    "                fingers = count(thresholded, segmented)\n",
    "\n",
    "                cv2.putText(clone, str(fingers), (70, 45), cv2.FONT_HERSHEY_SIMPLEX, 1, (0,0,255), 2)\n",
    "                \n",
    "                # show the thresholded image\n",
    "                cv2.imshow(\"Thesholded\", thresholded)\n",
    "\n",
    "        # draw the segmented hand\n",
    "        cv2.rectangle(clone, (left, top), (right, bottom), (0,255,0), 2)\n",
    "\n",
    "        # increment the number of frames\n",
    "        num_frames += 1\n",
    "\n",
    "        # display the frame with segmented hand\n",
    "        cv2.imshow(\"Video Feed\", clone)\n",
    "\n",
    "        # observe the keypress by the user\n",
    "        keypress = cv2.waitKey(1) & 0xFF\n",
    "\n",
    "        # if the user pressed \"q\", then stop looping\n",
    "        if keypress == ord(\"q\"):\n",
    "            break"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.4"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
